// DealTime.cpp: implementation of the Time class.
//
//////////////////////////////////////////////////////////////////////
//#include "stdafx.h"
#include <wchar.h>
#include "base_time.h"
#include <assert.h>
#include "milli_time.h"
#include "ht_except.h"
#include <string>

using namespace std;
HT_NAMESPACE_BEGIN

#define _MAX__TIME64_T     0x793406fffLL 
/**
 *	time_tʽʱֵ
 */
static inline unsigned long
linux_mktime (unsigned int year, unsigned int mon,
		unsigned int day, unsigned int hour,
		unsigned int min, unsigned int sec)
{
	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
		mon += 12;		/* Puts Feb last since it has leap day */
		year -= 1;
	}
	
	return (((
		(unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
		year*365 - 719499
		)*24 + hour /* now have hours */
		)*60 + min /* now have minutes */
		)*60 + sec; /* finally seconds */
}


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Mutex HT_CLASS_EXPORT Time::m_mutex;

Time::Time()
{
	m_time	=	time(NULL);
}

Time::Time(time_t tm)
{
	m_time	=	tm;
}

Time::Time(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec)
{
	if (SetUTCTime (nYear, nMonth, nDay, nHour, nMin, nSec))
	{
	#ifdef _WIN32
		_tzset ();
		m_time += _timezone;
	#else // _WIN32
		tzset ();
		m_time += timezone;		
	#endif // _WIN32
	}
}

bool Time::SetUTCTime (int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec)
{
	if ((nDay >= 1 && nDay <= 31)
		&& (nMonth >= 1 && nMonth <= 12)
		&& (nYear >= 1900))
	{
		m_time = linux_mktime (nYear, nMonth, nDay, nHour, nMin, nSec);
		return true;
	}

	m_time = -1;

	return false;
}

void Time::GetLocalTm(struct tm* lc) const
{
	HT_CS(m_mutex);
	*lc = *localtime(&m_time);
}

void Time::GetGmTm (struct tm* gm) const
{
	HT_CS(m_mutex);
	*gm = *gmtime(&m_time);
}

void Time::GetUTCTime (int &nYear, int &nMonth, int &nDay, int &nHour, int &nMin, int &nSec) const
{
	HT_CS(m_mutex);
	if (m_time > 0 && m_time <= _MAX__TIME64_T)
	{
		struct tm* gm = gmtime(&m_time);
		nYear = gm->tm_year + 1900;
		nMonth = gm->tm_mon + 1;
		nDay = gm->tm_mday;
		nHour = gm->tm_hour;
		nMin = gm->tm_min;
		nSec = gm->tm_sec;
	}
}

/**
 *	BFX_Timeм¼UTCʱ
 */
Time Time::GetCurrentTime ()
{
	return Time(time(NULL));
}

StdString Time::GetDisplayText() const
{
	StdString txt;
	if (m_time > 0 && m_time <= _MAX__TIME64_T )
	{
		txt.printf("%4d-%02d-%02d %02d:%02d:%02d",
			GetYear(), GetMonth(), GetDay(),
			GetHour(), GetMinute(), GetSecond());
	}
	return txt;
}

StdString Time::FormatUTC() const
{
	StdString txt;
	if (m_time > 0 && m_time <= _MAX__TIME64_T )
	{
		txt.printf("%4d-%02d-%02d %02d:%02d:%02d",
			GetUTCYear(), GetUTCMonth(), GetUTCDay(),
			GetUTCHour(), GetUTCMinute(), GetUTCSecond());
	}
	return txt;
}
/************************************************************************/
/* MilliTime
/************************************************************************/
std::string MilliTime::ToStringA ()
{
	StdString s;
	if (m_time > 0 && m_time <= _MAX__TIME64_T)
	{
		s.printf("%04d-%02d-%02d %02d:%02d:%02d.%03d", 
			GetUTCYear(), GetUTCMonth(), GetUTCDay(),
			GetUTCHour(), GetUTCMinute(), GetUTCSecond(), GetMillisecond());
	}
	
	return s;
}

std::wstring MilliTime::ToStringW ()
{
	wchar_t buf[30];
	if (m_time > 0 && m_time <= _MAX__TIME64_T )
	{
#ifdef _WIN32
		swprintf(buf, L"%04d-%02d-%02d %02d:%02d:%02d.%03d", 
			GetUTCYear(), GetUTCMonth(), GetUTCDay(),
			GetUTCHour(), GetUTCMinute(), GetUTCSecond(), GetMillisecond());
#else	// _WIN32
		swprintf(buf, 30, L"%04d-%02d-%02d %02d:%02d:%02d.%03d", 
			GetUTCYear(), GetUTCMonth(), GetUTCDay(),
			GetUTCHour(), GetUTCMinute(), GetUTCSecond(), GetMillisecond());
#endif	// _WIN32
	}
	return buf;
}

#ifdef _WIN32
#define my_wcstok wcstok
#else // _WIN32
long _wtoi(const wchar_t *ptr)
{
	wchar_t *end_ptr = NULL;
	return wcstol(ptr, &end_ptr, 10);
}

wchar_t *my_wcstok(wchar_t *wcs, const wchar_t *delim)
{
	static wchar_t *state = NULL;
	return wcstok (wcs, delim, &state);
}
#endif // _WIN32

bool MilliTime::ParseStrW (const wchar_t* str_in, int &nYear, int &nMonth, int &nDay, int &nHour, int &nMin, int &nSec, int &nMilli)
{
	wstring str(str_in);
	wchar_t seps1[]   = L"-/";
	wchar_t seps2[]   = L" ";
	wchar_t seps3[]   = L":";
	wchar_t seps4[]   = L".";

	int year = 0, mon = 0, day = 0, hour = 0, min = 0, sec = 0, milli = 0;
	int tmp;
	bool ok = false;
	wchar_t* tok = my_wcstok ((wchar_t *)str.c_str(), seps1);	// take year
	if (NULL != tok)
	{
		year = _wtoi(tok);
		tok = my_wcstok (NULL, seps1);	// take month
		if (NULL != tok)
		{
			mon = _wtoi (tok);
			tok = my_wcstok (NULL, seps2);	// take day
			if (NULL != tok)
			{
				day = _wtoi(tok);
				ok = true;
				tok = my_wcstok(NULL, seps3);	// take hour
				if (NULL != tok)
				{
					ok = false;
					hour = _wtoi(tok);
					tok = my_wcstok(NULL, seps3);	// take min
					if (NULL != tok)
					{
						min = _wtoi(tok);
						tok = my_wcstok(NULL, seps4);	// take second
						if (NULL != tok)
						{
							sec = _wtoi(tok);
							ok = true;
							tok = my_wcstok(NULL, seps4);	// take milli
							if (NULL != tok)
								milli = _wtoi(tok);
						}
					}
				}
			}
		}
	}

	if (ok)
	{
		nYear = year;
		nMonth = mon;
		nDay = day;
		nHour = hour;
		nMin = min;
		nSec = sec;
		nMilli = milli;
		return true;
	}

	return false;
}


bool MilliTime::ParseStrA (LPCTSTR str_in, int &nYear, int &nMonth, int &nDay, int &nHour, int &nMin, int &nSec, int &nMilli)
{
	string str(str_in);
	char seps1[]   = "-/";
	char seps2[]   = " ";
	char seps3[]   = ":";
	char seps4[]   = ".";

	int year = 0, mon = 0, day = 0, hour = 0, min = 0, sec = 0, milli = 0;
	int tmp;
	bool ok = false;
	const char* tok = strtok ((char *)str.c_str(), seps1);	// take year
	if (NULL != tok)
	{
		year = atoi(tok);
		tok = strtok (NULL, seps1);	// take month
		if (NULL != tok)
		{
			mon = atoi (tok);
			tok = strtok (NULL, seps2);	// take day
			if (NULL != tok)
			{
				day = atoi(tok);
				ok = true;
				tok = strtok(NULL, seps3);	// take hour
				if (NULL != tok)
				{
					ok = false;
					hour = atoi(tok);
					tok = strtok(NULL, seps3);	// take min
					if (NULL != tok)
					{
						min = atoi(tok);
						tok = strtok(NULL, seps4);	// take second
						if (NULL != tok)
						{
							sec = atoi(tok);
							ok = true;
							tok = strtok(NULL, seps4);	// take milli
							if (NULL != tok)
								milli = atoi(tok);
						}
					}
				}
			}
		}
	}

	if (ok)
	{
		nYear = year;
		nMonth = mon;
		nDay = day;
		nHour = hour;
		nMin = min;
		nSec = sec;
		nMilli = milli;
		return true;
	}

	return false;
}

void MilliTime::SetUTCByStringW (const wchar_t* str)
{
	int year = 0, mon = 0, day = 0, hour = 0, min = 0, sec = 0, milli = 0;
	if (ParseStrW(str, year, mon, day, hour, min, sec, milli))
	{
		SetUTCTime(year, mon, day, hour, min, sec);
		m_nMilli = milli;
	}
	else
		throw HT::Except (HT_DATETIME_FMT, "Datetime format error. used as yyyy-mm-dd HH:MM:SS.xxxx");
}

void MilliTime::SetLocalByStringW (const wchar_t* str)
{
	int year = 0, mon = 0, day = 0, hour = 0, min = 0, sec = 0, milli = 0;
	if (ParseStrW(str, year, mon, day, hour, min, sec, milli))
	{
		m_time = Time(year, mon, day, hour, min, sec).GetTime();
		m_nMilli = milli;
	}
	else
		throw HT::Except (HT_DATETIME_FMT, "Datetime format error. used as yyyy-mm-dd HH:MM:SS.xxxx");
}

void MilliTime::SetUTCByStringA(LPCTSTR str)
{
	int year = 0, mon = 0, day = 0, hour = 0, min = 0, sec = 0, milli = 0;
	if (ParseStrA(str, year, mon, day, hour, min, sec, milli))
	{
		SetUTCTime(year, mon, day, hour, min, sec);
		m_nMilli = milli;
	}
	else
		throw HT::Except (HT_DATETIME_FMT, "Datetime format error. used as yyyy-mm-dd HH:MM:SS.xxxx");
}

void MilliTime::SetLocalByStringA(LPCTSTR str)
{
	int year = 0, mon = 0, day = 0, hour = 0, min = 0, sec = 0, milli = 0;
	if (ParseStrA(str, year, mon, day, hour, min, sec, milli))
	{
		m_time = Time(year, mon, day, hour, min, sec).GetTime();
		m_nMilli = milli;
	}
	else
		throw HT::Except (HT_DATETIME_FMT, "Datetime format error. used as yyyy-mm-dd HH:MM:SS.xxxx");
}
HT_NAMESPACE_END
